<?php
/**
 * Model mapper for project builds.
 *
 * @category PhpCilux
 * @package  PhpCilux
 */

/**
 * Model mapper for project builds.
 *
 * @package PhpCilux
 */
class Model_BuildMapper
{

    /**
     * The build dir.
     *
     * @var string
     */
    protected $_buildDir;

    /**
     * The report dirname.
     *
     * @var string
     */
    protected $_reportDir = 'reports';

    /**
     * Hold the builds.
     *
     * @var array
     */
    protected $_builds;

    /**
     * Hold the commit log.
     *
     * @var array
     */
    protected $_commitLog;

    /**
     * Holds an instance of the class.
     *
     * @var Model_BuildMapper
     */
    protected static $_instance;

    /**
     * Singleton Getter.
     *
     * @return Model_BuildMapper
     */
    public static function &getInstance()
    {
        if (empty(self::$_instance)) {
            self::$_instance = new Model_BuildMapper();
        }

        return self::$_instance;
    }

    /**
     * Constructor.
     */
    public function __construct()
    {
        $this->_buildDir = APPLICATION_PATH  . DIRECTORY_SEPARATOR .
                            '..' . DIRECTORY_SEPARATOR .
                            'data' . DIRECTORY_SEPARATOR .
                            'build' . DIRECTORY_SEPARATOR;
    }

    /**
     * Load the builds of the given project.
     *
     * @param string $projectId The project key.
     * 
     * @return void
     */
    protected function _loadBuilds($projectId)
    {
        $dir = $this->_buildDir . $projectId . DIRECTORY_SEPARATOR . $this->_reportDir . DIRECTORY_SEPARATOR;

        if (!is_dir($dir)) {
            $this->_builds[$projectId] = array();
            return;
        }

        if (!empty($this->_builds[$projectId])) {
            return;
        }

        $files = scandir($dir);
        rsort($files);

        $this->_builds[$projectId] = array();
        while (list(,$file) = each($files)) {
            if (!in_array($file, array('..', '.')) && is_dir($dir . $file)) {
                $model = new Model_Build(array('projectKey' => $projectId, 'buildKey' => $file));
                $this->_builds[$projectId][$file] = $model;
            }
        }
    }

    /**
     * Get the last build of the given project.
     *
     * @param string $projectId The project key.
     * 
     * @return Model_Build
     */
    public function getLast($projectId)
    {
        $this->_loadBuilds($projectId);

        reset($this->_builds[$projectId]);
        while (list(,$build) = each($this->_builds[$projectId])) {
            return $build;
        }
    }

    /**
     * Get the previous builds.
     *
     * @param string $projectId The project key.
     * @param string $buildId   The build key.
     *
     * @return Model_Build
     */
    public function getBuild($projectId, $buildId)
    {
        $this->_loadBuilds($projectId);

        if (isset($this->_builds[$projectId][$buildId])) {
            return $this->_builds[$projectId][$buildId];
        }
    }

    /**
     * Get the previous builds.
     *
     * @param string  $projectId The project key.
     * @param string  $buildId   The build key.
     * @param integer $limit     Max count of wanted objects.
     *
     * @return array Array og Model_Build.
     */
    public function getPrevBuilds($projectId, $buildId, $limit)
    {
        $this->_loadBuilds($projectId);

        if (!array_key_exists($buildId, $this->_builds[$projectId])) {
            return array();
        }

        $searchPos = array_search($buildId, array_keys($this->_builds[$projectId]));

        return array_slice($this->_builds[$projectId], ($searchPos + 1), $limit);
    }

    /**
     * Get the log filename.
     *
     * @param string $projectId The project key.
     * @param string $build     The build key.
     * @param string $type      The logfile key (phpunit, phpcs).
     *
     * @return string
     */
    private function _getLogFileName($projectId, $build, $type)
    {
        $fileName = $this->_buildDir . $projectId . DIRECTORY_SEPARATOR .
                    $this->_reportDir . DIRECTORY_SEPARATOR .
                    $build . DIRECTORY_SEPARATOR;

        switch($type) {
            case 'phpunit':
                $fileName .= 'phpunit.txt';
                break;

            case 'phpcs':
                $fileName .= 'phpcs.txt';
                break;

            default:
                // Default.
                break;
        }

        return $fileName;
    }

    /**
     * Exits the log file.
     *
     * @param string $projectId The project key.
     * @param string $build     The build key.
     * @param string $type      The logfile key (phpunit, phpcs).
     *
     * @return boolean
     */
    public function exitsLog($projectId, $build, $type)
    {
        $fileName = $this->_getLogFileName($projectId, $build, $type);

        return is_file($fileName);
    }

    /**
     * Get the log file content.
     *
     * @param string $projectId The project key.
     * @param string $build     The build key.
     * @param string $type      The logfile key (phpunit, phpcs).
     *
     * @return string
     */
    public function getLog($projectId, $build, $type)
    {
        $fileName = $this->_getLogFileName($projectId, $build, $type);

        return file_get_contents($fileName);
    }

    /**
     * Get the commit comment.
     *
     * @param string $projectId The project key.
     * @param string $build     The build key.
     *
     * @return string
     */
    public function getCommitComment($projectId, $build)
    {
        $this->_loadCommitLog($projectId, $build);

        if (isset($this->_commitLog[$projectId][$build])) {
            return $this->_commitLog[$projectId][$build]['comment'];
        }
    }

    /**
     * Get the commit author.
     *
     * @param string $projectId The project key.
     * @param string $build     The build key.
     *
     * @return string
     */
    public function getCommitAuthor($projectId, $build)
    {
        $this->_loadCommitLog($projectId, $build);

        if (isset($this->_commitLog[$projectId][$build])) {
            return $this->_commitLog[$projectId][$build]['author'];
        }
    }

    /**
     * Get the commit time.
     *
     * @param string $projectId The project key.
     * @param string $build     The build key.
     *
     * @return string
     */
    public function getCommitTime($projectId, $build)
    {
        $this->_loadCommitLog($projectId, $build);

        if (isset($this->_commitLog[$projectId][$build])) {
            return $this->_commitLog[$projectId][$build]['time'];
        }
    }

    /**
     * Load the commit log.
     *
     * @param string $projectId The project key.
     * @param string $build     The build key.
     *
     * @return void
     */
    protected function _loadCommitLog($projectId, $build)
    {
        $dir = $this->_buildDir . $projectId . DIRECTORY_SEPARATOR .
               $this->_reportDir . DIRECTORY_SEPARATOR .
               $build . DIRECTORY_SEPARATOR;

        if (is_file($dir . 'svnlog.xml')) {
            $xml = simplexml_load_file($dir . 'svnlog.xml');

            $this->_commitLog[$projectId][$build] = array(
                'author'  => (string) $xml->logentry->author,
                'time'    => (string) $xml->logentry->date,
                'comment' => (string) $xml->logentry->msg,
            );
        }
    }

}